package com.gt.qr;

import java.text.DateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.DecodeHintType;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.ResultMetadataType;
import com.google.zxing.ResultPoint;
import com.google.zxing.ResultPointCallback;
import com.google.zxing.client.android.DecodeFormatManager;
import com.google.zxing.client.android.Intents;
import com.google.zxing.client.android.PlanarYUVLuminanceSource;
import com.google.zxing.client.android.PreferencesActivity;
import com.google.zxing.client.android.camera.CameraManager;
import com.google.zxing.client.android.result.ResultButtonListener;
import com.google.zxing.client.android.result.ResultHandler;
import com.google.zxing.client.android.result.ResultHandlerFactory;
import com.google.zxing.common.HybridBinarizer;

import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.preference.PreferenceManager;
import android.text.ClipboardManager;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

public class QrCodeHandler extends Handler implements ResultPointCallback {

	private static final String TAG = "QrCodeHandler";

	private static final int TIME_DELAY = 200;

	public static final int MSG_START = 100;
	public static final int MSG_RESTART = 101;
	public static final int MSG_SUCCESS = 102;
	public static final int MSG_FAIL = 103;
	public static final int MSG_QUIT = 104;
	public static final int MSG_DECODE = 200;
	public static final int MSG_AUTO_FOCUS = 201;

	private final Hashtable<DecodeHintType, Object> hints;
	private Vector<BarcodeFormat> decodeFormats;
	private final MultiFormatReader multiFormatReader;

	private static final String BARCODE_BITMAP = "BARCODE_BITMAP";

	private QrCodeCameraView qrCodeView;
	
	public QrCodeHandler(QrCodeCameraView view) {
		qrCodeView=view;
		
		multiFormatReader = new MultiFormatReader();
		hints = new Hashtable<DecodeHintType, Object>(3);

		decodeFormats = new Vector<BarcodeFormat>();
		decodeFormats.addAll(DecodeFormatManager.ONE_D_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.QR_CODE_FORMATS);
		decodeFormats.addAll(DecodeFormatManager.DATA_MATRIX_FORMATS);

		hints.put(DecodeHintType.POSSIBLE_FORMATS, decodeFormats);
		hints.put(DecodeHintType.NEED_RESULT_POINT_CALLBACK, this);

		multiFormatReader.setHints(hints);

		CameraManager.get().startPreview();
	}

	public void foundPossibleResultPoint(ResultPoint point) {
		// TODO
//		Log.i(TAG, "foundPossibleResultPoint>>>");
	}

	public void handleMessage(Message message) {
		switch (message.what) {
		case MSG_START:
			CameraManager.get().requestPreviewFrame(this, MSG_DECODE);
			CameraManager.get().requestAutoFocus(this, MSG_AUTO_FOCUS);
			break;
		case MSG_AUTO_FOCUS:
			CameraManager.get().requestAutoFocus(this, MSG_AUTO_FOCUS);
			break;
		case MSG_DECODE:
			decode((byte[]) message.obj, message.arg1, message.arg2);
			break;
		case MSG_SUCCESS:
			Log.e(TAG, "handleMessage>>>MSG_SUCCESS");
			Bundle bundle = message.getData();
			Bitmap barcode = bundle == null ? null : (Bitmap) bundle
					.getParcelable(BARCODE_BITMAP);
			handleDecode((Result) message.obj, barcode);
			break;
		case MSG_FAIL:
			CameraManager.get().requestPreviewFrame(this, MSG_DECODE);
			break;
		case MSG_QUIT:
			// CameraManager.get().stopPreview();
			break;
		}
	}

	private Bitmap lastBitmap=null;
	  
	  public Bitmap getLastBitmap(){
		  return lastBitmap;
	  }
	  
	private void decode(byte[] data, int width, int height) {
		long start = System.currentTimeMillis();
//		Log.i(TAG, "decode>>>"+data.length+";width:"+width+";height:"+height);
//		System.out.println("decode...." + data.length + "\twidth:" + width
//				+ "\theight:" + height);
		Result rawResult = null;
		PlanarYUVLuminanceSource source = CameraManager.get()
				.buildLuminanceSource(data, width, height);
		BinaryBitmap bitmap = new BinaryBitmap(new HybridBinarizer(source));
		try {
			rawResult = multiFormatReader.decodeWithState(bitmap);
		} catch (ReaderException re) {
			// continue
		} finally {
			multiFormatReader.reset();
		}

//		lastBitmap=source.renderCroppedGreyscaleBitmap();
		if (rawResult != null) {
			long end = System.currentTimeMillis();
			Log.d(TAG, "Found barcode (" + (end - start) + " ms):\n"
					+ rawResult.toString());
			Message message = Message.obtain(this, MSG_SUCCESS, rawResult);
			Bundle bundle = new Bundle();
			bundle.putParcelable(BARCODE_BITMAP,
					source.renderCroppedGreyscaleBitmap());
			message.setData(bundle);
			// Log.d(TAG, "Sending decode succeeded message...");
			message.sendToTarget();
		} else {
			Message message = Message.obtain(this, MSG_FAIL);
			message.sendToTarget();
		}
	}

	public void start() {
		removeMessages(MSG_START);
		sendEmptyMessageDelayed(MSG_START, TIME_DELAY);
	}

	public void stop() {
		removeMessages(MSG_START);
		removeMessages(MSG_RESTART);
		removeMessages(MSG_SUCCESS);
		removeMessages(MSG_FAIL);
		removeMessages(MSG_DECODE);
		removeMessages(MSG_AUTO_FOCUS);
		removeMessages(MSG_QUIT);// ????
	}

	private Result lastResult = null;
	
	public Result getLastResult(){
		return lastResult;
	}

	public void handleDecode(Result rawResult, Bitmap barcode) {
		lastResult = rawResult;
		if (barcode == null) {
			// This is from history -- no saved barcode
			handleDecodeInternally(rawResult, null);
		} else {
			handleDecodeInternally(rawResult, barcode);
		}
	}

	private void handleDecodeInternally(Result rawResult, Bitmap barcode) {
		
		qrCodeView.onQrCodeCatched(rawResult.getText());
		
//		ResultHandler resultHandler = ResultHandlerFactory.makeResultHandler(
//				this, rawResult);
//		TextView typeTextView = (TextView) findViewById(R.id.type_text_view);
//		typeTextView.setText(resultHandler.getType().toString());
//
//		DateFormat formatter = DateFormat.getDateTimeInstance(DateFormat.SHORT,
//				DateFormat.SHORT);
//		String formattedTime = formatter.format(new Date(rawResult
//				.getTimestamp()));
//		TextView timeTextView = (TextView) findViewById(R.id.time_text_view);
//		timeTextView.setText(formattedTime);
//
//		TextView metaTextView = (TextView) findViewById(R.id.meta_text_view);
//		View metaTextViewLabel = findViewById(R.id.meta_text_view_label);
//		metaTextView.setVisibility(View.GONE);
//		metaTextViewLabel.setVisibility(View.GONE);
//		Map<ResultMetadataType, Object> metadata = (Map<ResultMetadataType, Object>) rawResult
//				.getResultMetadata();
//		if (metadata != null) {
//			StringBuilder metadataText = new StringBuilder(20);
//			for (Map.Entry<ResultMetadataType, Object> entry : metadata
//					.entrySet()) {
//				if (DISPLAYABLE_METADATA_TYPES.contains(entry.getKey())) {
//					metadataText.append(entry.getValue()).append('\n');
//				}
//			}
//			if (metadataText.length() > 0) {
//				metadataText.setLength(metadataText.length() - 1);
//				metaTextView.setText(metadataText);
//				metaTextView.setVisibility(View.VISIBLE);
//				metaTextViewLabel.setVisibility(View.VISIBLE);
//			}
//		}
//
//		TextView contentsTextView = (TextView) findViewById(R.id.contents_text_view);
//		CharSequence displayContents = resultHandler.getDisplayContents();
//		contentsTextView.setText(displayContents);
//		// Crudely scale betweeen 22 and 32 -- bigger font for shorter text
//		int scaledSize = Math.max(22, 32 - displayContents.length() / 4);
//		contentsTextView.setTextSize(TypedValue.COMPLEX_UNIT_SP, scaledSize);
//
//		int buttonCount = resultHandler.getButtonCount();
//		ViewGroup buttonView = (ViewGroup) findViewById(R.id.result_button_view);
//		buttonView.requestFocus();
//		for (int x = 0; x < ResultHandler.MAX_BUTTON_COUNT; x++) {
//			TextView button = (TextView) buttonView.getChildAt(x);
//			if (x < buttonCount) {
//				button.setVisibility(View.VISIBLE);
//				button.setText(resultHandler.getButtonText(x));
//				button.setOnClickListener(new ResultButtonListener(
//						resultHandler, x));
//			} else {
//				button.setVisibility(View.GONE);
//			}
//		}
	}


}
